package com.xo.xodemo.controller.contract;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xo.xodemo.mapper.db1.ContractSigningMapper;
import com.xo.xodemo.mapper.db1.ProofBargainMapper;
import com.xo.xodemo.model.ContractSigningModel;
import com.xo.xodemo.model.ProofBargain;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;


@Slf4j
@RestController
@RequestMapping("/process")
public class Contract {
    @Autowired
    private ProofBargainMapper proofBargainMapper;

    @Autowired
    private ContractSigningMapper contractSigningMapper;

    @Value("${appId}")
    private String appId;

    @Value("${appKey}")
    private String appKey;

    @Value("${host}")
    private String host;

    @Value("${orgId}")
    private String orgId;


    /**
     * 获取到所有合同模版
     * 1获取全款模版
     * 2获取非全款模版
     * 0/null获取全部模版
     * xo - xo_e_contract
     * @return
     */
    @GetMapping("/contracts")
    public String getAllContracts(@RequestParam(value = "getContractId", required = false) String getContractId) {
        List<ContractSigningModel> contracts = contractSigningMapper.getAllContracts(getContractId);
        ObjectMapper mapper = new ObjectMapper();
        try {
            String json = mapper.writeValueAsString(contracts);
//            System.out.println("合同JSON: " + json);
            return json;
        } catch (JsonProcessingException e) {
            // 打印异常信息到控制台
            e.printStackTrace();
            return "获取合同列表失败";
        }
    }



    /**
     * 通过流程模板创建合同拟定和签署流程
     * 参考文档 https://open.esign.cn/doc/opendoc/file-and-template3/megwsgkmpbg1tec1
     * @param requestData
     * @return
     */
    @PostMapping("/postContract")
    public String postContract(@RequestBody Map<String, String> requestData ,String userId) {
        System.out.println("requestData = " + requestData);
        String contractName = requestData.get("contractName");  // 模版文件名称
        String templateId = requestData.get("templateId");  // 模版文件编号
        String contractId = requestData.get("contractId");  // 末班文件页数(PDF时使用根据页数设置)
        String oldAgreementNumber = requestData.get("oldAgreementNumber");

        // 根据ID查询客户信息 (PDF模版文件预填充使用)
        String id = requestData.get("id");
        ProofBargain pb = proofBargainMapper.selectById(id);
//        System.out.println("客户信息: " + pb);

        // 获取流程模板详情
        String signTemplatesDetail = signTemplatesDetail(templateId);

        // 获取签署2的participantId
        String getParticipantId = getParticipantId(signTemplatesDetail);

        // 个人创建账号接口地址
        String accountsApi = "/v3/sign-flow/create-by-sign-template";
        // 个人创建账号接口请求地址
        String accountsApiUrl = host + accountsApi;

        // 获取components(根据页数不同来填充不同的components控件)
        JSONArray components;
        if ("5".equals(contractId)) {
            components = buildComponents(signTemplatesDetail, pb);
        } else {
            components = buildComponentsFour(signTemplatesDetail, pb, oldAgreementNumber);
        }

        // 构建请求body体
        String result = null;
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("signTemplateId", templateId);

            JSONObject signFlowInitiator = new JSONObject();
            JSONObject transactor = new JSONObject();
            transactor.put("psnId", "9a57f844d36c4bb0b58cf7d1f273c622");
            signFlowInitiator.put("orgId", orgId);
            signFlowInitiator.put("transactor", transactor);
            jsonObject.put("signFlowInitiator", signFlowInitiator);

            JSONObject signFlowConfig = new JSONObject();
            signFlowConfig.put("signFlowTitle", contractName);
            signFlowConfig.put("autoFinish", true);
            signFlowConfig.put("autoStart", true);

            JSONObject noticeConfig = new JSONObject();
            noticeConfig.put("noticeTypes", "1");
            signFlowConfig.put("noticeConfig", noticeConfig);

            JSONObject signConfig = new JSONObject();
            signConfig.put("availableSignClientTypes", "2");
            signConfig.put("autoFillAndSubmit", true);
            signConfig.put("editComponentValue", false);
            signFlowConfig.put("signConfig", signConfig);

            JSONObject authConfig = new JSONObject();
            authConfig.put("psnAvailableAuthModes", new JSONArray()
                    .put("PSN_MOBILE3")
                    .put("PSN_FACE")
                    .put("PSN_BANKCARD4"));
            authConfig.put("orgAvailableAuthModes", new JSONArray()
                    .put("ORG_BANK_TRANSFER")
                    .put("ORG_LEGALREP")
                    .put("ORG_LEGALREP_AUTHORIZATION")
                    .put("ORG_ALIPAY_CREDIT"));
            signFlowConfig.put("authConfig", authConfig);

            jsonObject.put("signFlowConfig", signFlowConfig);

            JSONArray participants = new JSONArray();
            JSONObject participant = new JSONObject();
            participant.put("participantId", getParticipantId);



            JSONObject psnParticipant = new JSONObject();
            psnParticipant.put("psnAccount", pb.getTelephone());
            psnParticipant.put("psnName", pb.getName());
            participant.put("psnParticipant", psnParticipant);

            participants.put(participant);
            jsonObject.put("participants", participants);

            jsonObject.put("components", components);
            String reqBodyData = jsonObject.toString();
            System.out.println(reqBodyData);
            // 对请求Body体内的数据计算ContentMD5
            String contentMD5 = doContentMD5(reqBodyData);

            // 构建待签名字符串
            String method = "POST";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = accountsApi;
            String date = "";
            String headers = "";

            StringBuffer sb = new StringBuffer();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();
            // 计算请求签名值
            String reqSignature = doSignatureBase64(plaintext, appKey);

            // 获取时间戳(精确到毫秒)
            long timeStamp = timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put("X-Tsign-Open-App-Id", appId);
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送POST请求
            result = HTTPHelper.sendPOST(accountsApiUrl, reqBodyData, header, "UTF-8");
            System.out.println("发送POST请求返回" + result);

            // 获取返回值中的 signFlowId 的值保存到数据库
            JSONObject jsonObj = new JSONObject(result);
            String signFlowId = jsonObj.getJSONObject("data").getString("signFlowId");
            contractSigningMapper.insertSignFlowId(pb.getName(),signFlowId,userId);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("流程模板创建合同拟定和签署流程: {0}", e.getMessage());
            System.out.println(msg);
            return result;
        }
    }


    /**
     * 构建components部分(4页)
     * @param signTemplatesDetail
     * @param pb
     * @param oldAgreementNumber
     * @return
     */
    private JSONArray buildComponentsFour(String signTemplatesDetail, ProofBargain pb, String oldAgreementNumber) {
        // 获取协议编号
        String agreementNumber = agreementNumber();
        // 创建ObjectMapper实例
        ObjectMapper componentsMapper = new ObjectMapper();
        // 解析JSON数据为JsonNode对象
        JsonNode rootNode = null;
        try {
            rootNode = componentsMapper.readTree(signTemplatesDetail);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        // 获取components字段
        JsonNode componentsNode = rootNode.get("data").get("participants").get(0).get("components");
        List<Map<String, String>> resultList = new ArrayList<>();
        for (JsonNode component : componentsNode) {
            Map<String, String> map = new HashMap<>();
            map.put("componentId", component.get("componentId").asText());
            map.put("componentName", component.get("componentName").asText());
            map.put("fileId", component.get("fileId").asText());
            resultList.add(map);
        }
        String componentsList = null;
        try {
            componentsList = componentsMapper.writeValueAsString(resultList);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        JSONArray componentsLists = new JSONArray(componentsList);
        JSONArray components = new JSONArray();

        for (int i = 0; i < componentsLists.length(); i++) {
            JSONObject component = componentsLists.getJSONObject(i);
            String componentName = component.getString("componentName");

            if ("乙方姓名".equals(componentName)) {
                JSONObject component1 = new JSONObject();
                component1.put("fileId", component.getString("fileId"));
                component1.put("componentId", component.getString("componentId"));
                component1.put("componentValue", pb.getName());
                components.put(component1);
            } else if ("手机号".equals(componentName)) {
                JSONObject component2 = new JSONObject();
                component2.put("fileId", component.getString("fileId"));
                component2.put("componentId", component.getString("componentId"));
                component2.put("componentValue", pb.getTelephone());
                components.put(component2);
            } else if ("多行文本".equals(componentName)) {
                JSONObject component3 = new JSONObject();
                component3.put("fileId", component.getString("fileId"));
                component3.put("componentId", component.getString("componentId"));
                component3.put("componentValue", pb.getAddress());
                components.put(component3);
            } else if ("身份证号1".equals(componentName)) {
                JSONObject component4 = new JSONObject();
                component4.put("fileId", component.getString("fileId"));
                component4.put("componentId", component.getString("componentId"));
                component4.put("componentValue", pb.getIdCard());
                components.put(component4);
            } else if ("身份证号2".equals(componentName)) {
                JSONObject component5 = new JSONObject();
                component5.put("fileId", component.getString("fileId"));
                component5.put("componentId", component.getString("componentId"));
                component5.put("componentValue", pb.getIdCard());
                components.put(component5);
            } else if ("协议编号1".equals(componentName)) {
                JSONObject component6 = new JSONObject();
                component6.put("fileId", component.getString("fileId"));
                component6.put("componentId", component.getString("componentId"));
                component6.put("componentValue", agreementNumber);
                components.put(component6);
            } else if ("协议编号2".equals(componentName)) {
                JSONObject component7 = new JSONObject();
                component7.put("fileId", component.getString("fileId"));
                component7.put("componentId", component.getString("componentId"));
                component7.put("componentValue", agreementNumber);
                components.put(component7);
            } else if ("协议编号3".equals(componentName)) {
                JSONObject component8 = new JSONObject();
                component8.put("fileId", component.getString("fileId"));
                component8.put("componentId", component.getString("componentId"));
                component8.put("componentValue", agreementNumber);
                components.put(component8);
            } else if ("协议编号4".equals(componentName)) {
                JSONObject component9 = new JSONObject();
                component9.put("fileId", component.getString("fileId"));
                component9.put("componentId", component.getString("componentId"));
                component9.put("componentValue", agreementNumber);
                components.put(component9);
            } else if ("旧协议编号".equals(componentName)) {
                JSONObject component10 = new JSONObject();
                component10.put("fileId", component.getString("fileId"));
                component10.put("componentId", component.getString("componentId"));
                component10.put("componentValue", oldAgreementNumber);
                components.put(component10);
            }
        }

        return components;
    }


    /**
     * 构建components部分(5页)
     * @param signTemplatesDetail
     * @param pb
     * @return
     */
    private JSONArray buildComponents(String signTemplatesDetail, ProofBargain pb) {
        // 获取协议编号
        String agreementNumber = agreementNumber();
        // 创建ObjectMapper实例
        ObjectMapper componentsMapper = new ObjectMapper();
        // 解析JSON数据为JsonNode对象
        JsonNode rootNode = null;
        try {
            rootNode = componentsMapper.readTree(signTemplatesDetail);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        // 获取components字段
        JsonNode componentsNode = rootNode.get("data").get("participants").get(0).get("components");
        List<Map<String, String>> resultList = new ArrayList<>();
        for (JsonNode component : componentsNode) {
            Map<String, String> map = new HashMap<>();
            map.put("componentId", component.get("componentId").asText());
            map.put("componentName", component.get("componentName").asText());
            map.put("fileId", component.get("fileId").asText());
            resultList.add(map);
        }
        String componentsList = null;
        try {
            componentsList = componentsMapper.writeValueAsString(resultList);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        JSONArray componentsLists = new JSONArray(componentsList);
        JSONArray components = new JSONArray();

        for (int i = 0; i < componentsLists.length(); i++) {
            JSONObject component = componentsLists.getJSONObject(i);
            String componentName = component.getString("componentName");

            if ("乙方姓名".equals(componentName)) {
                JSONObject component1 = new JSONObject();
                component1.put("fileId", component.getString("fileId"));
                component1.put("componentId", component.getString("componentId"));
                component1.put("componentValue", pb.getName());
                components.put(component1);
            } else if ("手机号".equals(componentName)) {
                JSONObject component2 = new JSONObject();
                component2.put("fileId", component.getString("fileId"));
                component2.put("componentId", component.getString("componentId"));
                component2.put("componentValue", pb.getTelephone());
                components.put(component2);
            } else if ("多行文本".equals(componentName)) {
                JSONObject component3 = new JSONObject();
                component3.put("fileId", component.getString("fileId"));
                component3.put("componentId", component.getString("componentId"));
                component3.put("componentValue", pb.getAddress());
                components.put(component3);
            } else if ("身份证号1".equals(componentName)) {
                JSONObject component4 = new JSONObject();
                component4.put("fileId", component.getString("fileId"));
                component4.put("componentId", component.getString("componentId"));
                component4.put("componentValue", pb.getIdCard());
                components.put(component4);
            } else if ("身份证号2".equals(componentName)) {
                JSONObject component5 = new JSONObject();
                component5.put("fileId", component.getString("fileId"));
                component5.put("componentId", component.getString("componentId"));
                component5.put("componentValue", pb.getIdCard());
                components.put(component5);
            } else if ("协议编号1".equals(componentName)) {
                JSONObject component6 = new JSONObject();
                component6.put("fileId", component.getString("fileId"));
                component6.put("componentId", component.getString("componentId"));
                component6.put("componentValue", agreementNumber);
                components.put(component6);
            } else if ("协议编号2".equals(componentName)) {
                JSONObject component7 = new JSONObject();
                component7.put("fileId", component.getString("fileId"));
                component7.put("componentId", component.getString("componentId"));
                component7.put("componentValue", agreementNumber);
                components.put(component7);
            } else if ("协议编号3".equals(componentName)) {
                JSONObject component8 = new JSONObject();
                component8.put("fileId", component.getString("fileId"));
                component8.put("componentId", component.getString("componentId"));
                component8.put("componentValue", agreementNumber);
                components.put(component8);
            } else if ("协议编号4".equals(componentName)) {
                JSONObject component9 = new JSONObject();
                component9.put("fileId", component.getString("fileId"));
                component9.put("componentId", component.getString("componentId"));
                component9.put("componentValue", agreementNumber);
                components.put(component9);
            } else if ("协议编号5".equals(componentName)) {
                JSONObject component10 = new JSONObject();
                component10.put("fileId", component.getString("fileId"));
                component10.put("componentId", component.getString("componentId"));
                component10.put("componentValue", agreementNumber);
                components.put(component10);
            }
        }

        return components;
    }

    /**
     * 获取签署2的participantId
     * @param signTemplatesDetail
     * @return
     */
    public String getParticipantId(String signTemplatesDetail) {
        // 创建ObjectMapper实例
        ObjectMapper componentsMapper = new ObjectMapper();
        // 解析JSON数据为JsonNode对象
        JsonNode rootNode = null;
        try {
            rootNode = componentsMapper.readTree(signTemplatesDetail);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        JsonNode participantsNode = rootNode.get("data").get("participants");
        for (JsonNode participant : participantsNode) {
            String participantFlag = participant.get("participantFlag").asText();
            if (participantFlag.equals("签署方2")) {
                String participantId = participant.get("participantId").asText();
                return participantId;
            }
        }
        return null; // 如果未找到匹配的参与者，返回null或抛出异常，视情况而定
    }


    /**
     * 查询流程模板详情
     * @return
     */
    public String signTemplatesDetail(String signTemplateId){
        // 个人创建账号接口地址
        String getUrl = "/v3/sign-templates/detail";
        // 完整的请求地址
        String getAllUrl = host + getUrl;

        try {
            // 文档这么写的GET请求时ContentMD5为"" 实际为1B2M2Y8AsgTpgAmY7PhCfg==
            String contentMD5 = "1B2M2Y8AsgTpgAmY7PhCfg==";
            // 构建待签名字符串
            String method = "GET";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = String.format("/v3/sign-templates/detail?orgId=%s&queryComponents=true&signTemplateId=%s", orgId, signTemplateId);
            String date = "";
            String headers = "";

            StringBuffer sb = new StringBuffer();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();

            // 获取发送的 JSON 字符串
            HashMap<String, Object> query = new HashMap<String, Object>();
            query.put("orgId", orgId);  // 机构账号
            query.put("queryComponents", true);
            query.put("signTemplateId", signTemplateId);

            // 计算请求签名值
            String reqSignature = doSignatureBase64(plaintext, appKey);

            // 获取时间戳(精确到毫秒)
            long timeStamp = timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put("X-Tsign-Open-App-Id", appId);
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送GET请求，并记录实际返回的 JSON 字符串
            String result = HTTPHelper.sendGet(getAllUrl, query, header, "UTF-8");
//            System.out.println("查询流程模板详情请求返回信息： " + result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("查询流程模板详情调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
            return msg;
        }
    }


    /**
     * 测 试
     * @param args
     */
//    public static void main(String[] args) {
//        String signFlowId = "9668070d490d4c4bb462608e001549f8";
//        String result = fileDownloadUrl(signFlowId);
//        System.out.println(result);
//
//    }


    /**
     * 下载已签署文件及附属材料 传递参数userId 查询对应的数据
     * 接口描述: 流程结束后，获取签署完成的文件以及相关附属材料的下载链接。
     *         未签署完成的流程，无法下载相关文件，否则会报错："流程非签署完成状态，不允许下载文档"。
     * @return
     */
    @GetMapping("/fileDownloadUrl")
    public String fileDownloadUrl(String userId){
        String signFlowId = contractSigningMapper.selectSignFlowId(userId);
//        System.out.println(signFlowId);
        // 个人创建账号接口地址
        String getUrl = "/v3/sign-flow/"+signFlowId+"/file-download-url";
        // 完整的请求地址
        String getAllUrl = "https://smlopenapi.esign.cn" + getUrl;

        try {
            // 文档这么写的GET请求时ContentMD5为"" 实际为1B2M2Y8AsgTpgAmY7PhCfg==
            String contentMD5 = "1B2M2Y8AsgTpgAmY7PhCfg==";
            // 构建待签名字符串
            String method = "GET";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = String.format("/v3/sign-flow/%s/file-download-url", signFlowId);
            String date = "";
            String headers = "";

            StringBuffer sb = new StringBuffer();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();

            // 获取发送的 JSON 字符串
            HashMap<String, Object> query = new HashMap<String, Object>();
//            query.put("signFlowId", signFlowId);  // 已完成状态的签署流程ID

            // 计算请求签名值
            String reqSignature = doSignatureBase64(plaintext, appKey);
//            System.out.println(reqSignature);

            // 获取时间戳(精确到毫秒)
            long timeStamp = timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put("X-Tsign-Open-App-Id", "7438998229");
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送GET请求，并记录实际返回的 JSON 字符串
            String result = HTTPHelper.sendGet(getAllUrl, query, header, "UTF-8");
            // 从返回值中获取 downloadUrl
            JSONObject jsonResult = new JSONObject(result);
            JSONArray filesArray = jsonResult.getJSONObject("data").getJSONArray("files");
            JSONObject fileObject = filesArray.getJSONObject(0);
            String downloadUrl = fileObject.getString("downloadUrl");
//            System.out.println("下载已签署文件及附属材料： " + result);
            return downloadUrl;
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("下载已签署文件及附属材料接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
            return msg;
        }
    }









    /***
     *
     * @param str 待计算的消息
     * @return MD5计算后摘要值的Base64编码(ContentMD5)
     * @throws Exception 加密过程中的异常信息
     */
    public static String doContentMD5(String str) throws Exception {
        byte[] md5Bytes = null;
        MessageDigest md5 = null;
        String contentMD5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md5.update(str.getBytes("UTF-8"));
            // 获取文件MD5的二进制数组（128位）
            md5Bytes = md5.digest();
            // 把MD5摘要后的二进制数组md5Bytes使用Base64进行编码（而不是对32位的16进制字符串进行编码）
            contentMD5 = new String(org.apache.commons.codec.binary.Base64.encodeBase64(md5Bytes), "UTF-8");
        } catch (NoSuchAlgorithmException e) {
            String msg = MessageFormat.format("不支持此算法: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        } catch (UnsupportedEncodingException e) {
            String msg = MessageFormat.format("不支持的字符编码: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        }
        return contentMD5;
    }

    /***
     * 计算请求签名值
     *
     * @param message 待计算的消息
     * @param secret 密钥
     * @return HmacSHA256计算后摘要值的Base64编码
     * @throws Exception 加密过程中的异常信息
     */
    public static String doSignatureBase64(String message, String secret) throws Exception {
        String algorithm = "HmacSHA256";
        Mac hmacSha256;
        String digestBase64 = null;
//        secret = "67389c850d591406cd4e2a78c5214753";
        try {
            hmacSha256 = Mac.getInstance(algorithm);
            byte[] keyBytes = secret.getBytes("UTF-8");
            byte[] messageBytes = message.getBytes("UTF-8");
            hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm));
            // 使用HmacSHA256对二进制数据消息Bytes计算摘要
            byte[] digestBytes = hmacSha256.doFinal(messageBytes);
            // 把摘要后的结果digestBytes转换成十六进制的字符串
            // String digestBase64 = Hex.encodeHexString(digestBytes);
            // 把摘要后的结果digestBytes使用Base64进行编码
            digestBase64 = new String(Base64.encodeBase64(digestBytes), "UTF-8");
        } catch (NoSuchAlgorithmException e) {
            String msg = MessageFormat.format("不支持此算法: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        } catch (UnsupportedEncodingException e) {
            String msg = MessageFormat.format("不支持的字符编码: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        } catch (InvalidKeyException e) {
            String msg = MessageFormat.format("无效的密钥规范: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        }
        return digestBase64;
    }

    /***
     * 获取时间戳(毫秒级)
     *
     * @return 毫秒级时间戳,如 1578446909000
     */
    public static long timeStamp() {
        long timeStamp = System.currentTimeMillis();
        return timeStamp;
    }

    /**
     * 生成协议编号
     *
     * @return
     */
    public static String agreementNumber() {
        Date currentDate = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMddHHmm");
        String formattedDate = dateFormat.format(currentDate);
        Random random = new Random();
        int randomNum = random.nextInt(10000);
        String result = "YCJR" + formattedDate + String.format("%04d", randomNum);
        return result;
    }

    /***
     * 计算文件的Content-MD5
     * @param filePath 文件路径
     * @return
     */
    public static String getFileContentMD5(String filePath) {
        // 获取文件MD5的二进制数组（128位）
        byte[] bytes = getFileMD5Bytes128(filePath);
        // 对文件MD5的二进制数组进行base64编码
        return new String(Base64.encodeBase64(bytes));
    }

    /***
     * 获取文件MD5-二进制数组（128位）
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public static byte[] getFileMD5Bytes128(String filePath) {
        FileInputStream fis = null;
        byte[] md5Bytes = null;
        try {
            File file = new File(filePath);
            fis = new FileInputStream(file);
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = fis.read(buffer, 0, 1024)) != -1) {
                md5.update(buffer, 0, length);
            }
            md5Bytes = md5.digest();
            fis.close();
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return md5Bytes;
    }





}
